/********************************************************************************
* 
*	Project Name : S3C6410 Validation
*
*	Copyright 2008 by Samsung Electronics, Inc.
*	All rights reserved.
*
*	Project Description :
*		This software is only for verifying functions of the S3C6400.
*		Anybody can use this software without our permission.
*  
*--------------------------------------------------------------------------------
* 
*	File Name : AC97_test.c
*  
*	File Description :
*
*	Author	: Sung-Hyun, Na
*	Dept. : AP Development Team
*	Created Date : 2008/02/19
*	Version : 0.2
* 
*	History
*	- Version 0.1 (Sung-Hyun.Na, 2008/02/19)
*	  	-> Working On SMDK6400 Rev 0.2 Board
*	- Version 0.2 (Sung-Hyun.Na, 2008/02/19)
*		-> Working On SMDK6410 Board
*		
*	Board Configuration for Connection AP and AC97 Codec.
*	- 1. SMDK6400 Rev0.0, Rev0.1 Rev 0.2 - CFG1, CFG2
*		- 1.1 CFG1 : CFG1 selects path of Analogue Audio Jacks(Speak Out, Mic -In and Line-In) On SMDK Base B'd andAC97 Codec(WM9713).
*		 	Up to SW1, 2 and 3 of the CFG1.
*			- 1.2 CFG2 : CFG2 selects path of AP Audio Ports(GPD, GPE) to Codec. 
*			 	- 1.2.1 Audio Port0(GPD) - A97 Codec
*					Up to SW1, and 2 of the CFG2. 
*				- 1.2.1 Audio Port1(GPE) - A97 Codec
*					Down to SW1, and 2 of the CFG2. 
*
*	- 2. SMDK6410 Rev0.0, Rev0.1 Rev0.2, Rev1.0 - CFG1, CFG2
*		- 2.1 CFG1 : CFG1 selects path of Analogue Audio Jacks(Speak Out, Mic -In and Line-In) On SMDK Base B'd and AC97 Codec(WM9713).
*		 	Up to SW1, 2 and 3 of the CFG1.
*			- 2.2 CFG2 : CFG2 selects path of AP Audio Ports(GPD, GPE) to Codecs on SMDK6410 Base B'd and External Codec Connector(Module 4)  
*				-2.2.1 Codec on SMDK
*					You Should Be Removed R48 and R67 to disconnect Audio Path to the Module 4 Connector.
*					Becasue Loading of This Path affect BITCLK of AC-Link, that is AC-Link is Down.
*			 		- 2.2.1.1 Audio Port0(GPD) - A97 Codec
*						Down to SW1 of the CFG2. 
*						Down to SW2 of the CFG2.
*					- 2.2.1.2 Audio Port1(GPE) - A97 Codec
*						Up to SW1 of the CFG2. 
*						Down to SW3 of the CFG2.
*				-2.2.2 External Codec Connector (Module4)
*					Check R44 ~ R48 or R63 ~ R67. It must be Connected.
*			 		- 2.2.2.1 Audio Port0(GPD) - Module4
*						Up to SW2 of the CFG2.
*					- 2.2.2.2 Audio Port1(GPE) - A97 Codec
*						Up to SW3 of the CFG2.
********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "def.h"
#include "option.h"
#include "library.h"
#include "sfr6410.h"
#include "system.h"
#include "gpio.h"
#include "intc.h"
#include "dma.h"
#include "timer.h"

#include "ac97.h"
#include "audio.h"

void AC97_DispTestInfor(void);
void AC97Conf_Codec(void);
void AC97Conf_SelectADCSource(void);
void AC97Conf_SelectSamplingRate(void);
void AC97Conf_DMAUnit(void);
void AC97Conf_DMAUnitChannel(void);
void AC97Conf_Addr(void);
void AC97Conf_SelectIntr(void);


//Test Functions
void AC97_Test(void);
void AC97_Configuration(AUDIO_PORT);

static u8 AC97_Powerdown(AUDIO_PORT);
static u8 AC97_CodecRegisterRW(AUDIO_PORT);

static u8 AC97_IntrPcmIn(AUDIO_PORT);
static u8 AC97_IntrMicIn(AUDIO_PORT);
static u8 AC97_IntrPcmOut(AUDIO_PORT);

static u8 AC97_DmaPcmIn(AUDIO_PORT ePort);
static u8 AC97_DmaMicIn(AUDIO_PORT ePort);
static u8 AC97_DmaPcmOut(AUDIO_PORT ePort);
static u8 AC97_DmaByPass1(AUDIO_PORT ePort);
static u8 AC97_DmaByPass2(AUDIO_PORT ePort);
//////////
// Function Name : AC97_Test
// Function Description : 
//   	This function calls Test Function of AC97 Controller and configure Test Condition
// Input : 	None
// Output : None.
//Version : 0.5
void AC97_Test(void)
{	
	AUDIO_PORT ePort = AUDIO_PORT0;	
	const AC97testFuncMenu ac97_function[]=
	{
		0,         					"Exit\n",
		AC97_Configuration,		"AC97 Controller Configuration\n"
		,
		AC97_Powerdown,			"AC97 Power Down Test",
		AC97_CodecRegisterRW,	"AC97 Calculate Delay Time\n",

		AC97_IntrPcmIn,			"Interrupt Mode : PCM In(Slot3/4)",
		AC97_IntrMicIn,			"Interrupt Mode : MIC In(Slot6)",
		AC97_IntrPcmOut,			"Interrupt Mode : PCM Out(Slot3/4)\n",
		
		AC97_DmaPcmIn,			"DMA Mode : PCM In(Slot3/4)",
		AC97_DmaMicIn,			"DMA Moee : MIC In(Slot6)",
		AC97_DmaPcmOut,			"DMA Mode : PCM Out(Slot3/4)\n",
		
		AC97_DmaByPass1,			"DMA Mode : Bypass through In Slot 3/4 to Out Slot 3/4",		
		AC97_DmaByPass2,			"DMA Mode : Bypass through In Slot 6 to Out Slot 3/4",		
		0,							 0
	};	
	AC97_Init(); 
	AC97_SetPort(AUDIO_PORT0);
	AC97_ClosePort(AUDIO_PORT1);
	Delay(1000);	
	while (1)
	{
		u32 i, nSel;
		UART_Printf("\n===================================================================\n");
		AC97_DispTestInfor();		
		UART_Printf("======================== AC97 Tes Function ========================\n\n");
		for (i=0; (int)(ac97_function[i].desc)!=0; i++)
		{
			UART_Printf("%2d: %s\n", i,ac97_function[i].desc);
		}
		UART_Printf("\n%2d: Change Port\n",i++);
		UART_Printf("==================================================================\n");	
		UART_Printf("\nSelect the function to test : ");
		nSel = UART_GetIntNum();
		UART_Printf("\n");
		if (nSel == 0)
			break;
		if (nSel>0 && nSel<(sizeof(ac97_function)/8-1))
			 (ac97_function[nSel].func)(ePort);
		else if ( nSel == (sizeof(ac97_function)/8-1))
		{	
			if (ePort == AUDIO_PORT0)
			{
				AC97_ClosePort(AUDIO_PORT0);
				AC97_SetPort(AUDIO_PORT1);				
				ePort = AUDIO_PORT1;
			}
			else 
			{
				AC97_ClosePort(AUDIO_PORT1);
				AC97_SetPort(AUDIO_PORT0);				
				ePort = AUDIO_PORT0;
			}
		}
	}	
}

//////////
// Function Name : AC97_Configuration
// Function Description : 
//   This function configuration test condition.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.5
void AC97_Configuration(AUDIO_PORT ePort)
{
	u32 uCountFunc=0;
	s32 iSel=0;	
	const testFuncMenu aAC97ConfigFunc[] =
	{
		//AC97 Configuration Item
		AC97Conf_Codec,					"Audio Codec for A97",
		AC97Conf_SelectADCSource,		"Audio Source",
		AC97Conf_SelectSamplingRate,	"Sample Rate\n",
		
		AC97Conf_DMAUnit,				"DMA Controller",
		AC97Conf_DMAUnitChannel,		"DMA Channel",
		AC97Conf_Addr,					"Memory Address\n",
		
		AC97Conf_SelectSamplingRate,	"Sampling Frequency(VRA On/Off) ",	
		AC97Conf_SelectIntr,				"Interrupt Source ",				
	    	0,0
	};
	UART_Printf("\n\n================== AC97 Configuration =====================\n\n");
	while(1)
	{
		for (uCountFunc=0; (u32)(aAC97ConfigFunc[uCountFunc].desc)!=0; uCountFunc++)
			UART_Printf("%2d: %s\n", uCountFunc, aAC97ConfigFunc[uCountFunc].desc);

		UART_Printf("\nSelect the function to test : ");
		iSel =UART_GetIntNum();
		UART_Printf("\n");
		if(iSel == -1)
		{
			break;
		}
		(aAC97ConfigFunc[iSel].func) ();		
	}
}

//////////
// Function Name : AC97_Powerdown
// Function Description : 
//   This function test AC-Link Power Down State Machine
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_Powerdown(AUDIO_PORT ePort)
{
	if(AC97_InitACLINK())
	{
		//Normal
	 	UART_Printf("\n=>Normal\n");
	 	AC97_ControllerState();
	 	UART_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));
		UART_Getc();
	 	
	 	//ADCs off
	 	UART_Printf("\n=>ADCs off PR0\n");
		AC97_CodecCmd(WRITE,0x26,(1<<8));
	 	AC97_ControllerState();
		UART_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));
		UART_Getc();
	 	
	 	//DACs off
	 	UART_Printf("\n=>DACs off PR1\n");
	 	AC97_CodecCmd(WRITE,0x26,(1<<8)|(1<<9));
	 	AC97_ControllerState();
	 	UART_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	
		UART_Getc();
	 	
	 	//Analog off
	 	UART_Printf("\n=>Analog off PR2 & PR3\n");
	 	AC97_CodecCmd(WRITE,0x26,(1<<8)|(1<<9)|(1<<10));
	 	AC97_ControllerState();
	 	UART_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_CodecCmd(READ,0x26,0x0000));	
	 	UART_Getc();
	 	
	 	//Digital I/F off
	 	UART_Printf("\n=>Digital I/F off PR4\n");
	 	AC97_CodecCmd(WRITE,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
	 	AC97_ControllerState();
	 	UART_Getc();
		
	 	//Shut off AC-Link
	 	UART_Printf("\n=>Shut off AC-Link\n");							//Hold AC-link data
	 	AC97_ShuntOffAcLink();	 	
	 	AC97_ControllerState();
	 	UART_Printf("\nPress enter key for Warm Reset\n");
	 	UART_Getc();
		
		//Cold Reset Test;
		AC97_ColdReset();
	
		//Warm Reset
		AC97_WarmReset();		
		return TRUE;
	}
	else 
		return FALSE;			
}

//////////
// Function Name : AC97_CodecRegisterRW
// Function Description : 
//   This function calculate delay for operation of Read or Write AC97 Codec register
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_CodecRegisterRW(AUDIO_PORT ePort)
{
	u32 uCmdOffset = 0;
	u16 uCmdData = 0xf;
	u32 uWritedelay = 1;
	u32 uReadDelay = 1;
	u16 uState = 0;
	u16 uCodecStat = 0;
	
	if(AC97_InitACLINK())
	{
		while(1)
		{	
			UART_Printf("Write Delay Time is %d\n",uWritedelay);
			UART_Printf("Read Delay Time is %d\n",uReadDelay);
			uCmdOffset = (rand() % 0x20) / 2 * 2;
			AC97_CodecCmd(WRITE,uCmdOffset,0x1);
			//Write
			AC97_CodecCmdNoDelay(WRITE,uCmdOffset,uCmdData);
			DelayfrTimer(micro,uWritedelay);			
			//Read
			AC97_CodecCmdNoDelay(READ,uCmdOffset,0);
			DelayfrTimer(micro,uWritedelay);	
			AC97_CodecStatRegister(&uState, &uCodecStat);			
			//Delay(uDebugdelay);
			if (uCmdData == uCodecStat)
			{
				UART_Printf("Matched!!\n");				
				break;
			}
			else 
			{
				UART_Printf("Not matched!! Read Register Value is 0x%x\n", uCodecStat);
				uWritedelay++;
				#if 0
				if (uWritedelay % 2)
					uWritedelay++;			
				else
					uReadDelay++;
				#endif
			}
		}		
		return TRUE;
	}
	else 
		return FALSE;
}

//////////
// Function Name : AC97_IntrPcmIn
// Function Description : 
//   This function Recoding PCM Binary  through PCM-In(slot 3,4) using interrupt.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_IntrPcmIn(AUDIO_PORT ePort)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if(AC97_InitACLINK())
	{	
		if ( pInfor->m_eADCSource == LINEIN )
			UART_Printf("Supply Sound to AC97 CODEC via Line In Connector.\n");
		else
			UART_Printf("Supply Sound to AC97 CODEC via MIC In Connector.\n");
	   	UART_Printf("Press any key to record.\n");
		UART_Getc();
	   	UART_Printf("Recording...\n");	
		WM9713_CodecInitPCMIn(ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			
		AC97_InitBuffer(PCM_IN, pInfor->m_pPCMInStartAddr, pInfor->m_uPCMInSize);
		//Initial Interrupt Controller
		INTC_ClearVectAddr();
		INTC_SetVectAddr(NUM_AC97, ISR_AC97);
		INTC_Enable(NUM_AC97);
		// Transfer data enable  using AC-Link
		AC97_SetTransferCh(PCM_IN, PIO);	
		// Set AC97 Controller to generate IRQ
		AC97_ClearInt(pInfor->m_ePCMInIntMode);
		AC97_IntrCon(pInfor->m_ePCMInIntMode, ENABLE);		
		AC97_SetIntrDone(pInfor->m_ePCMInIntMode,FALSE);
		while(1)
		{
		      if(AC97_GetIntrDone(pInfor->m_ePCMInIntMode) == 1)
				break;	
		}
		AC97_IntrCon(pInfor->m_ePCMInIntMode, DISABLE);
		AC97_SetTransferCh(PCM_IN, OFF);					//Disable Transfer PCM Out data on AC - Link
		INTC_Disable(NUM_AC97);		
		UART_Printf("\nRecording Done\n");
		return TRUE;
	}
	else
	{
		UART_Printf("AC-Link is not activated\n");
		return FALSE;
	}

}

//////////
// Function Name : AC97_IntrMicIn
// Function Description : 
//   This function Recoding PCM Binary through MIC-In(slot6) using interrupt.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_IntrMicIn(AUDIO_PORT ePort)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if(AC97_InitACLINK())
	{	
		if ( pInfor->m_eADCSource == LINEIN )
			UART_Printf("Supply Sound to AC97 CODEC via Line In Connector.\n");
		else
			UART_Printf("Supply Sound to AC97 CODEC via MIC In Connector.\n");
	   	UART_Printf("Press any key to record.\n");
		UART_Getc();
	   	UART_Printf("Recording...\n");	
		WM9713_CodecInitPCMIn(ACLinkSlot6, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			
		AC97_InitBuffer(MIC_IN, pInfor->m_pMICInStartAddr, pInfor->m_uMICInSize);
		//Initial Interrupt Controller
		INTC_ClearVectAddr();
		INTC_SetVectAddr(NUM_AC97, ISR_AC97);		
		INTC_Enable(NUM_AC97);			
		// Transfer data enable  using AC-Link
		AC97_SetTransferCh(MIC_IN, PIO);	
		// Set AC97 Controller to generate IRQ
		AC97_ClearInt(pInfor->m_eMICInIntMode);
		AC97_IntrCon(pInfor->m_eMICInIntMode, ENABLE);				
		AC97_SetIntrDone(pInfor->m_eMICInIntMode,FALSE);
		while(1)
		{
		      if(AC97_GetIntrDone(pInfor->m_eMICInIntMode) == 1)
				break;	
		}
		AC97_IntrCon(pInfor->m_eMICInIntMode, DISABLE);
		AC97_SetTransferCh(MIC_IN, OFF);					//Disable Transfer PCM Out data on AC - Link
		INTC_Disable(NUM_AC97);		
		UART_Printf("\nRecording Done\n");
		return TRUE;
	}
	else
	{
		UART_Printf("AC-Link is not activated\n");
		return FALSE;
	}

}

//////////
// Function Name : AC97_IntrPcmOut
// Function Description : 
//   This function Play PCM Binary through PCM-Out(slot 3,4) using PCM-Out interrupt.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_IntrPcmOut(AUDIO_PORT ePort)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	u32 uCnt;
	u32 uData;
	if(AC97_InitACLINK())
	{	
		UART_Printf("\nListen to Sound via Speak Out Connector.\n");
		UART_Printf("Press any key to play.\n");
	    	UART_Getc();
	   	UART_Printf("\nNow Play...\n");
		UART_Printf("Headphone Volume Register = 0x%x\n", pInfor->m_uOutputVolume);
		WM9713_InitPCMOut(ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, CodecPort_1st);
		AC97_InitBuffer(PCM_OUT, pInfor->m_pPCMOutStartAddr, pInfor->m_uPCMOutSize);
	    	//IRQ Initialization
		INTC_ClearVectAddr();
		INTC_SetVectAddr(NUM_AC97, ISR_AC97);
		INTC_Enable(NUM_AC97);	
		AC97_SetTransferCh(PCM_OUT, PIO);						//Enable AC-Link to transfer data 
		for(uCnt = 0; uCnt < PCM_OUT_TRIGGER; uCnt++)
		{	
			if(AC97_PopDataMem(PCM_OUT, &uData) <= 0)  			
				break;		
			AC97_SetDataFifo(uData);
		}	
		AC97_ClearInt(pInfor->m_ePCMOutIntMode);				//Enable AC97 Controller to generate IRQ
		AC97_IntrCon(pInfor->m_ePCMOutIntMode, ENABLE);		
		AC97_SetIntrDone(pInfor->m_ePCMOutIntMode,FALSE);
		while(1)
		{
		     if(AC97_GetIntrDone(pInfor->m_ePCMOutIntMode) == TRUE)
				break;	
		}
		AC97_IntrCon(pInfor->m_ePCMOutIntMode, DISABLE);		//Disable AC97 Controller to generate IRQ
		AC97_SetTransferCh(PCM_OUT, OFF);						//Disable Transfer PCM Out data on AC - Link
		INTC_Disable(NUM_AC97);								//Disable Interrupt Controller
		UART_Printf("\nEnd of Play!\n");
		AC97_ExitCodecPCMIn(1);
		return TRUE;
	}
	else
	{
		UART_Printf("AC-Link is not activated. please check CFG2 Switch\n");
		return FALSE;
	}
}


//////////
// Function Name : AC97_DmaPcmIn
// Function Description : 
//   This function Recoding through PCM-In(slot 3,4) using PCM-Out DMA Request.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_DmaPcmIn(AUDIO_PORT ePort)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if(AC97_InitACLINK())
	{	
		UART_Printf("Supply Sound to AC97 CODEC via Line In Connector.\n");
		UART_Printf("Press any key to record.\n");
		UART_Getc();
		UART_Printf("Recording...\n");	
		
		//WM9713_CodecInitPCMIn(ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);	
		WM9713_CodecInit(AUDIO_Rx, ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
		
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_AC97DmaDone);
		AC97_InitDMA(PCM_IN);
		AC97_DMAIntrClr(PCM_IN);
		AC97_SetTransferCh(PCM_IN, DMA);			// Enable AC- Link to transfer PCM data 
		AC97_SetIntrDone(PCMIN_THRESHOLD_INT, FALSE);
		do
		{
			UART_Printf(".");
			Delay(3000);
		}while(!AC97_GetIntrDone(PCMIN_THRESHOLD_INT));
		AC97_SetTransferCh(PCM_IN, OFF);		//AC97 PCM In Channel Finish 
		AC97_DMAStop(PCM_IN);
		INTC_Disable(pInfor->m_uNumDma);			
		UART_Printf("\nEnd of Record!\n");		
		AC97_ExitCodecPCMIn(1);		
		return TRUE;
	}
	else
	{
		UART_Printf("AC-Link is not activated. please check CFG2 Switch\n");
		return FALSE;
	}
}

//////////
// Function Name : AC97_DmaMicIn
// Function Description : 
//   This function Recoding through PCM-In(slot6) using DMA Request.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_DmaMicIn(AUDIO_PORT ePort)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	if(AC97_InitACLINK())
	{	
		UART_Printf("Supply Sound to AC97 CODEC via Line In Connector.\n");
		UART_Printf("Press any key to record.\n");
		UART_Getc();
		UART_Printf("Recording...\n");	
		
		//WM9713_CodecInitPCMIn(ACLinkSlot6, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);	
		WM9713_CodecInit(AUDIO_Rx, ACLinkSlot6, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
		
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_AC97DmaDone);
		
		AC97_InitDMA(MIC_IN);
		AC97_DMAIntrClr(MIC_IN);
		AC97_SetTransferCh(MIC_IN, DMA);						// Enable AC- Link to transfer PCM data 
		AC97_SetIntrDone(MICIN_THRESHOLD_INT, FALSE);
		do
		{
			UART_Printf(".");
			Delay(3000);
		}while(!AC97_GetIntrDone(MICIN_THRESHOLD_INT));
		AC97_SetTransferCh(MIC_IN, OFF);						//AC97 MIC In Channel Finish 
		AC97_DMAStop(MIC_IN);
		INTC_Disable(pInfor->m_uNumDma);			
		UART_Printf("\nEnd of Record!\n");		
		AC97_ExitCodecPCMIn(1);		
		return TRUE;
	}
	else
	{
		UART_Printf("AC-Link is not activated. please check CFG2 Switch\n");
		return FALSE;
	}
}


//////////
// Function Name : AC97_DmaPcmOut
// Function Description : 
//   This function Play PCM Binary through PCM-Out(slot 3,4) using DMA Request.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_DmaPcmOut(AUDIO_PORT ePort)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	u8 uKeyinput;
	if(AC97_InitACLINK())
	{	
		UART_Printf("\nListen to Sound via Speak Out Connector.\n");
		UART_Printf("Press any key to play.\n");
		UART_Getc();
		UART_Printf("\nNow Play...\n");
		UART_Printf("To Volume Up, Press the 'u' key.\n");
		UART_Printf("To Volume Down, Press the 'd' key.\n");
		UART_Printf("To Command  Codec Manually,  Press the 's' key.\n");
		UART_Printf("\nIf you want to exit, Press the 'x' key.\n");
		UART_Printf("Headphone Volume Register = 0x%x\n", pInfor->m_uOutputVolume);		
		
		//WM9713_InitPCMOut(ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, CodecPort_1st);		
		WM9713_CodecInit(AUDIO_Tx, ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
		
		//Set DMA
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_AC97DmaRestart);
		AC97_InitDMA(PCM_OUT);
		AC97_DMAIntrClr(PCM_OUT);
		AC97_SetTransferCh(PCM_OUT, DMA);			// Enable AC- Link to transfer PCM data 	
		while(1)
		{
			uKeyinput = UART_Getc();
			if( (uKeyinput == 'x') | (uKeyinput == 'X')) 
				break;
			else if ((uKeyinput == 'd') | (uKeyinput == 'D') | (uKeyinput == 'u') | (uKeyinput == 'U'))
				AC97_SetOutputVolume(uKeyinput);
			else if ((uKeyinput == 's') | (uKeyinput == 'S'))
				AC97_CodecCmdManually();					
		} 	
		//Disable to Transfer PCM Data on AC -Link
		AC97_SetTransferCh(PCM_OUT, OFF);
		// Stop DMA
		AC97_DMAStop(PCM_OUT);
		INTC_Disable(pInfor->m_uNumDma);	
		UART_Printf("\nEnd of Play!\n");	
		AC97_ExitCodecPCMIn(1);
		return TRUE;
	}
	else
		return FALSE;
	
}

//////////
// Function Name : AC97_DmaByPass1
// Function Description : 
//   This function record PCM Binary through PCM-In(slot 3,4) and play the PCM Binary through PCM-OUT(slot3,4) using DMA Request.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_DmaByPass1(AUDIO_PORT ePort)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	u8 uKeyinput;
	if(AC97_InitACLINK())
	{
		UART_Printf("Supply Sound to AC97 CODEC via Line In Connector.\n");
		UART_Printf("\nListen to Sound via Speak Out Connector.\n");
		UART_Getc();
		WM9713_CodecInit(AUDIO_TxRx, ACLinkSlot34, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_AC97DmaRestart);
		#if 0
		// DMA Initilieze for AC97 PCM Out 
		AC97_InitDMA(PCM_OUT);
		AC97_DMAIntrClr(PCM_OUT);
		AC97_SetTransferCh(PCM_OUT, DMA);		// Enable AC- Link to transfer PCM data 	
		Delay(2000);
		// DMA Initilieze for AC97 PCM In 
		AC97_InitDMA(PCM_IN);
		AC97_DMAIntrClr(PCM_IN);
		AC97_SetTransferCh(PCM_IN, DMA);			// Enable AC- Link to transfer PCM data 
		#else 		
		// DMA Initilieze for AC97 PCM In 
		AC97_InitDMA(PCM_IN);
		AC97_DMAIntrClr(PCM_IN);
		AC97_SetTransferCh(PCM_IN, DMA);			// Enable AC- Link to transfer PCM data 
		Delay(2000);
		// DMA Initilieze for AC97 PCM Out 
		AC97_InitDMA(PCM_OUT);
		AC97_DMAIntrClr(PCM_OUT);
		AC97_SetTransferCh(PCM_OUT, DMA);		// Enable AC- Link to transfer PCM data 			
		#endif
		while(1)
		{
			uKeyinput = UART_Getc();
			if( (uKeyinput == 'x') | (uKeyinput == 'X')) 
				break;
			else if ((uKeyinput == 'd') | (uKeyinput == 'D') | (uKeyinput == 'u') | (uKeyinput == 'U'))
				AC97_SetOutputVolume(uKeyinput);
			else if ((uKeyinput == 's') | (uKeyinput == 'S'))
				AC97_CodecCmdManually();					
		} 	
		AC97_SetTransferCh(PCM_OUT, OFF);
		AC97_DMAStop(PCM_OUT);
		AC97_SetTransferCh(PCM_IN, OFF);		//AC97 PCM In Channel Finish 
		AC97_DMAStop(PCM_IN);		
		INTC_Disable(pInfor->m_uNumDma);	
		AC97_ExitCodecPCMIn(1);
		return TRUE;
	}
	else
	{
		UART_Printf("AC-Link is not activated. please check connnectino of AP and AC97 Codec\n");
		return FALSE;
	}
}

//////////
// Function Name : AC97_DmaByPass2
// Function Description : 
//   This function record PCM Binary through MIC-In(Slot6) and play the PCM Binary through PCM-OUT(slot3,4) using DMA Request.
// Input : 	ePort - Audio Contorller Number
// Output : None
// Version : v0.1
static u8 AC97_DmaByPass2(AUDIO_PORT ePort)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	u8 uKeyinput;
	if(AC97_InitACLINK())
	{
		UART_Printf("Supply Sound to AC97 CODEC via Line In Connector.\n");
		UART_Printf("\nListen to Sound via Speak Out Connector.\n");
		UART_Getc();
		WM9713_CodecInit(AUDIO_TxRx, ACLinkSlot6, pInfor->m_uSamplingRate, Master, Word16, pInfor->m_eADCSource, CodecPort_1st);			// Codec Initialize
		INTC_SetVectAddr(pInfor->m_uNumDma, Isr_AC97DmaRestart);
		// DMA Initilieze for AC97 MIC In 
		AC97_InitDMA(MIC_IN);
		AC97_DMAIntrClr(MIC_IN);
		AC97_SetTransferCh(MIC_IN, DMA);			// Enable AC- Link to transfer MIC data 
		Delay(1000);
		// DMA Initilieze for AC97 PCM Out 
		AC97_InitDMA(PCM_OUT);
		AC97_DMAIntrClr(PCM_OUT);
		AC97_SetTransferCh(PCM_OUT, DMA);		// Enable AC- Link to transfer PCM data 	
		while(1)
		{
			uKeyinput = UART_Getc();
			if( (uKeyinput == 'x') | (uKeyinput == 'X')) 
				break;
			else if ((uKeyinput == 'd') | (uKeyinput == 'D') | (uKeyinput == 'u') | (uKeyinput == 'U'))
				AC97_SetOutputVolume(uKeyinput);
			else if ((uKeyinput == 's') | (uKeyinput == 'S'))
				AC97_CodecCmdManually();					
		} 	
		AC97_SetTransferCh(PCM_OUT, OFF);
		AC97_DMAStop(PCM_OUT);
		AC97_SetTransferCh(MIC_IN, OFF);		//AC97 PCM In Channel Finish 
		AC97_DMAStop(MIC_IN);		
		INTC_Disable(pInfor->m_uNumDma);	
		AC97_ExitCodecPCMIn(1);
		return TRUE;
	}
	else
	{
		UART_Printf("AC-Link is not activated. please check connnectino of AP and AC97 Codec\n");
		return FALSE;
	}
}

//////////
// Function Name : AC97_DispTestInfor
// Function Description : 
//   This function diplay Test Condition of AC97 Controller. SMDK.
// Input : 	ePort ->  I2S Controller
// Output : None
// Version : 0.0
void AC97_DispTestInfor(void)
{
	AC97_Infor* pInfor = AC97_GetInfor();
	UART_Printf("Sampling Frequency : %3.1fKHz\n",(double)(pInfor->m_uSamplingRate)/1000);
	UART_Printf("PCM Out Int source : ");
	if ( pInfor->m_ePCMOutIntMode == PCMOUT_UNDERRUN_INT)
		UART_Printf("Under Run\n");
	else 
		UART_Printf("Threshold\n");
	UART_Printf("PCM In Int Source : ");
	if ( pInfor->m_ePCMOutIntMode == PCMIN_OVERRUN_INT)
		UART_Printf("Over Run\n");
	else 
		UART_Printf("Threshold\n");
	UART_Printf("MIC In Int Source : ");
	if ( pInfor->m_ePCMOutIntMode == MICIN_OVERRUN_INT)
		UART_Printf("Over Run\n");
	else 
		UART_Printf("Threshold\n");			
}


//////////
// Function Name : AC97Conf_Codec
// Function Description : 
//   This function configurate SMDK.
// Input : 	ePort ->  I2S Controller
// Output : None
// Version : 0.0
// Example 
// PCMConf_Addr(AUDIO_PORT1);
void AC97Conf_Codec(void)
{
	s32 uSelection;
	do
	{
		UART_Printf("Select Audio Codec for PCM I/Fl\n");
		UART_Printf("0: AK2430	1: WM9713	2: WM8753	3: STAC9767	4: WM8580	5: WM8990\n");
		uSelection = UART_GetIntNum();
	}while(!(uSelection == 1 && uSelection == 3));	
	AC97_GetInfor()->m_uCodecID = (AudioCodec) uSelection;
}

//////////
// Function Name : PCMConf_DMAUnit
// Function Description : 
//   This function selects DMA Controller
// Input : 	ePort ->  I2S Controller
// Output : None
// Version : 0.0
// Example 
// I2SConf_SelDMAUnit(AUDIO_PORT1);
void AC97Conf_DMAUnit(void)
{	
	s32 uSelection;
	do{
		UART_Printf("Select DMA\n");
		UART_Printf("0. Normal DMA		1. Secure DMA\n");
		uSelection = UART_GetIntNum();
	}while(!(uSelection >= 0 && uSelection <= 1));
	
	if ( uSelection == 0 )
		AC97_SetDMAUnit(DMA1);	
	else	
		AC97_SetDMAUnit(SDMA1);
}

//////////
// Function Name : AC97Conf_DMAUnitChannel
// Function Description : 
//   This function selects DMA Controller
// Input : 	None
// Output : None
// Version : 0.0
// Example 
// I2SConf_SelDMAUnit(AUDIO_PORT1);
void AC97Conf_DMAUnitChannel(void)
{	
	s32 uSelection;
	s32 sChSel;
	DMA_CH	uCh;
	AC97_Infor* pInfor = AC97_GetInfor();
	do
	{
		do
		{
			UART_Printf("Select PCM Interface Channel\n");
			UART_Printf("0: MIC In(Slot3,4)	1: PCM In(Slot6)	2:PCM Out(Slot3,4) \n");
			sChSel = UART_GetIntNum();
		}while(!(sChSel >= 0 && sChSel <= 2));
		UART_Printf("\nSelect Channel : 0:CH A, 1:CH B, 2:CH C, 3:CH D, 4:CH E, 5:CH F, 6:CH G, 7:CH H	: ");
		uSelection=UART_GetIntNum();
		UART_Printf("\n");	
	}while(!(uSelection >= 0 && uSelection <= 7));
	switch(uSelection)
	{
		case 0: 	uCh = DMA_A;	break;             
		case 1: 	uCh = DMA_B;	break;
		case 2: 	uCh = DMA_C;	break;
		case 3: 	uCh = DMA_D;	break;	     	
		case 4: 	uCh = DMA_E;	break;
		case 5: 	uCh = DMA_F;	break;
		case 6: 	uCh = DMA_G;	break;
		case 7: 	uCh = DMA_H;	break;				
		default : Assert(0);
	}
	if ( (AC97_CHANNEL)(8 + 2 * sChSel) == PCM_OUT)		pInfor->m_eAc97PCMOutCh = uCh;
	else if ( (AC97_CHANNEL)(8 + 2 * sChSel) == PCM_IN)	pInfor->m_eAc97PCMInCh = uCh;
	else if ( (AC97_CHANNEL)(8 + 2 * sChSel) == MIC_IN)	pInfor->m_eAc97MICInCh = uCh;
	else Assert(0);
}


//////////
// Function Name : AC97Conf_Addr
// Function Description : 
//   This function set PCM Data Address.
// Input : 	None
// Output : None
// Version : 0.0
// Example 
// PCMConf_Addr(AUDIO_PORT1);
void AC97Conf_Addr(void)
{
	s32 sChSel;
	u32 uTempAddr;
	s32 uTempSize;
	AC97_Infor *pInfor = AC97_GetInfor();
	do
	{
		UART_Printf("Select PCM Interface Channel\n");
		UART_Printf("0: MIC In(Slot6)	1: PCM In(Slot3, 4)	2:PCM Out(Slot3,4) \n");
		sChSel = UART_GetIntNum();
	}while(!(sChSel >= 0 && sChSel <= 2));	
	UART_Printf("Enter the new temporary address(0x...):");
	uTempAddr = (u32) UART_GetIntNum();
	if ( uTempAddr == 0xffffffff )
		uTempAddr = 0x5100002c;
	UART_Printf("Enter the new size that is multiple of 4(0x4 ~ 0xfffff):");
	uTempSize = (u32) UART_GetIntNum();
	if ( uTempSize < 0x4 ||  uTempSize > 0xfffff )
		uTempAddr = 0xfffff;	
	uTempSize = (uTempSize / 4) * 4;
	if ( sChSel == 0 )		 	// MIC-In
	{
		pInfor->m_pMICInStartAddr = (u32 *)uTempAddr;
		pInfor->m_uMICInSize = (s32) uTempAddr;
	}
	else if ( sChSel == 1 )	 // PCM-In
	{
		pInfor->m_pPCMInStartAddr = (u32 *)uTempAddr;
		pInfor->m_uPCMInSize = (s32) uTempAddr;
	}
	else 					// PCM-Out
	{
		pInfor->m_pPCMOutStartAddr = (u32 *)uTempAddr;
		pInfor->m_uPCMOutSize = (s32) uTempAddr;
	}	
}


//////////
// Function Name : AC97Conf_Addr
// Function Description : 
//   This function set PCM Data Address.
// Input : 	None
// Output : None
// Version : 0.0
// Example 
// PCMConf_Addr(AUDIO_PORT1);
void AC97Conf_SelectSamplingRate(void)
{
	u32 uSel;
	AC97_Infor * pInfor = AC97_GetInfor();
	UART_Printf("Current Sample Rate is %dHz\n",pInfor->m_uSamplingRate);	
	while(1)
	{
		UART_Printf("Enter ADC/DAC sample Rate(8000 ~ 48000)[Hz]\n");
		uSel = UART_GetIntNum();
		if ( uSel >= 8000 && uSel <= 48000 )
			break;
	}
	pInfor->m_uSamplingRate = uSel;
}

//////////
// Function Name : AC97Conf_Addr
// Function Description : 
//   This function set PCM Data Address.
// Input : 	None
// Output : None
// Version : 0.0
// Example 
// PCMConf_Addr(AUDIO_PORT1);
void AC97Conf_SelectIntr(void)
{	
	AC97_CHANNEL eCH;
	u32 uSelTemp0;
	UART_Printf("Select Channel\n");
	UART_Printf("0. PCM Out	1. PCM In	2.MIC In\n");
	eCH = (AC97_CHANNEL)UART_GetIntNum();
	UART_Printf("Select Interrupt Mode\n");
	UART_Printf("0: Full[D]	1: Half\n");
	uSelTemp0 = UART_GetIntNum();
	AC97_SetIntrMode(eCH, (AC97_INT)(uSelTemp0 * 3 + (u32) eCH));	
}


//////////
// Function Name : AC97Conf_SelectADCSource
// Function Description : 
//   This function set PCM Data Address.
// Input : 	None
// Output : None
// Version : 0.0
// Example 
// PCMConf_Addr(AUDIO_PORT1);
void AC97Conf_SelectADCSource(void)
{
	AC97_Infor * pInfor = AC97_GetInfor();
	s32 sSel;
	do
	{
		Disp("Select Audio Source\n");
		Disp("0 : Line In	1 : Mic In\n");
		sSel = (AudioSource) UART_GetIntNum();
	}while(!(sSel >= 0 && sSel <= 1));	
	pInfor->m_eADCSource = (AudioSource) sSel;
}
